﻿
#region Copyright & License
// --------------------------
// Copyright 2008 Daniel Gray
// --------------------------
// This file is part of Kale.
//
// Kale is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Kale is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with Kale.  If not, see <http://www.gnu.org/licenses/>.
#endregion
#region File details
// --------------------------------------------------------
// Filename          : ImageResizer.cs
// Author            : Daniel Gray
// Created           : 15/04/2008
// --------------------------------------------------------
#endregion
            
using System;
using System.Collections.Generic;
using System.Linq;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.IO;

namespace Kale.Core
{
   public static class ImageResizer
   {
      public static byte[] ResizeImage(Image image, ImageFormat imageFormat, Size targetSize)
      {
			EncoderParameters encoderParams = null;
			ImageCodecInfo encoder = null;
			Image newImage = null;
			Size newSize = GetNewSize(image.Size, targetSize);

			bool isIndexed = false;

         if (image.PixelFormat == PixelFormat.Format1bppIndexed) isIndexed = true;
         if (image.PixelFormat == PixelFormat.Format4bppIndexed) isIndexed = true;
         if (image.PixelFormat == PixelFormat.Format8bppIndexed) isIndexed = true;
         if (image.PixelFormat == PixelFormat.Indexed) isIndexed = true;

         try
         {
            using (MemoryStream stream = new MemoryStream())
            {
               if (imageFormat == ImageFormat.Jpeg && !isIndexed)
               {
                  // we're doing a jpeg...
                  newImage = new Bitmap(newSize.Width, newSize.Height, image.PixelFormat);
                  Graphics g = Graphics.FromImage(newImage);
                  g.CompositingQuality = CompositingQuality.HighQuality;
                  g.SmoothingMode = SmoothingMode.AntiAlias;
                  g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                  g.PixelOffsetMode = PixelOffsetMode.HighQuality;
                  Rectangle r = new Rectangle(0, 0, newSize.Width, newSize.Height);
                  g.FillRectangle(Brushes.White, 0, 0, newSize.Width, newSize.Height);
                  g.DrawImage(image, r);
                  newImage.Save(stream, ImageFormat.Jpeg);
               }
               else
               {
                  // doing a png output...
                  encoder = _getEncoder("image/png");
                  encoderParams = new EncoderParameters(1);
                  encoderParams.Param[0] = new EncoderParameter(Encoder.Quality, 100);
                  System.Drawing.Image.GetThumbnailImageAbort dummy = new System.Drawing.Image.GetThumbnailImageAbort(ThumbnailCallback);
                  newImage = image.GetThumbnailImage(newSize.Width, newSize.Height, dummy, IntPtr.Zero);
                  newImage.Save(stream, encoder, encoderParams);
               }

               stream.Seek(0, SeekOrigin.Begin);
               // read the contents of the image
               byte[] resizedImage = new byte[stream.Length];
               stream.Read(resizedImage, 0, (int)stream.Length);
               return resizedImage;
            }
         }
         finally
         {
            if (newImage != null) newImage.Dispose();
         }
      }

      /// <summary>
      /// Calculates the size of the new image based on current property values
      /// and the sizes contained in the specified image.
      /// </summary>
      /// <param name="img">Image to calculate new size for.</param>
      /// <returns>The calculated new size.</returns>
      public static Size GetNewSize(Size currentSize, Size newSize)
      {

         int newWidth = currentSize.Width;
         int newHeight = currentSize.Height;
         float aspectRatio = GetAspectRatio(currentSize);

         // if the width is greater or equal to the height - resize to width, otherwise to the height...
         if (newWidth >= newHeight)
         {
            newWidth = newSize.Width;
            newHeight = (int)(newWidth * aspectRatio);
         }
         else
         {
            newHeight = newSize.Height;
            newWidth = (int)(newHeight / aspectRatio);
         }

         return new Size(newWidth, newHeight);
      }

      /// <summary>
      /// Calculates the aspect ratio for the specified size.
      /// </summary>
      /// <param name="s">Size to calculate aspect ratio from.</param>
      /// <returns>Calculated aspect ratio.</returns>
      public static float GetAspectRatio(Size s)
      {
         float fW = (float)s.Width;
         float fH = (float)s.Height;

         float r = fH / fW;

         return r;
      }

		/// <summary>
		/// Gets an encode for the specified mime type.
		/// </summary>
		/// <param name="mimeType">Mime type to get encoder for.</param>
		/// <returns>A suitable encoder; <b>null</b> if no encoder can be found.</returns>
		private static ImageCodecInfo _getEncoder(string mimeType)
		{
			foreach(ImageCodecInfo encoder in ImageCodecInfo.GetImageEncoders())
			{
				if (encoder.MimeType == mimeType) return encoder;
			}
			return null;
		}

      /// <summary>
      /// Provides a method for the thumbnail routine to call back to.
      /// </summary>
      /// <remarks>This is a dummy method.</remarks>
      /// <returns><b>false</b>, always.</returns>
      private static bool ThumbnailCallback()
      {
         return false;
      }
   }
}
